package remote

import (
	"github.com/sirupsen/logrus"
	"github.com/ingopansa/userinfoservice/tokenprovider"
	"github.com/ingopansa/userinfoservice/model"
	"net/http"
	"bytes"
	"encoding/json"
	"crypto/tls"
)

type Config struct {
	ClientID 			string	`json:"clientID"`
	ClientSecret 		string	`json:"clientSecret"`
	IntrospectionURL 	string	`json:"introspectionURL"`
	AllowInsecureSSL	bool	`json:"allowInsecureSSL"`
}

type remoteTokenProvider struct {
	logger 				logrus.FieldLogger
	client				*http.Client
	clientID 			string
	clientSecret 		string
	url					string
}

// Open always returns a new in memory storage.
func (c *Config) Open(logger logrus.FieldLogger) (tokenprovider.TokenProvider, error) {
	logger.Debugf( "Opening remote token provider" )

	client := &http.Client{}

	if c.AllowInsecureSSL {
		logger.Infof("Allowing insecure SSL\n")
		http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}


	return &remoteTokenProvider{
		logger: 			logger,
		client: 			client,
		clientID: 			c.ClientID,
		clientSecret: 		c.ClientSecret,
		url: 				c.IntrospectionURL,
	}, nil
}

func (c *remoteTokenProvider)Introspect(accessToken string)(model.AccessTokenData, error){
	c.logger.Debugf("remoteTokenProvider.Introspect() - provided accessToken: %v", accessToken )

	accessTokenString := []byte("token="+accessToken+"&token_type_hint=access_token")
	if request, err := http.NewRequest("POST", c.url, bytes.NewBuffer(accessTokenString)); err != nil {
		c.logger.Errorf("error building request: %v", err)
		return model.AccessTokenData{}, err
	} else {
		request.SetBasicAuth(c.clientID, c.clientSecret)
		request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

		if response, err := c.client.Do(request); err != nil {
			c.logger.Errorf("error executing request: %v", err)
			return model.AccessTokenData{}, err
		} else {
			var accessTokenData model.AccessTokenData

			if err := json.NewDecoder(response.Body).Decode(&accessTokenData); err != nil {
				c.logger.Errorf("error parsing JSON result: %v", err)
				return model.AccessTokenData{}, err
			} else {
				defer response.Body.Close()

				c.logger.Debugf( "access token active: %v\n", accessTokenData.Active )
				if accessTokenData.Active {
					c.logger.Debugf( "  sub: %v\n", accessTokenData.Sub )
					c.logger.Debugf( "  scope: %v\n", accessTokenData.Scope )
				}

				return accessTokenData, nil
			}
		}
	}
}